# -*- coding: UTF-8 -*-
import os
import stat
import paramiko

from lj_tool import tool_try

from . import lj_bean_conn, tool_cache, tool_log


class LJSsh:
    def __init__(self, bean_conn: lj_bean_conn.BeanConn) -> None:
        self.bean_conn = bean_conn
        # 创建连接池对象
        self.pool = []
        self.count = 0
        self.ex_count = 0
        print(f"LJ - 初始化 ssh 链接对象...")

    def gen_conn(self):
        try:
            client = paramiko.SSHClient()
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            # 连接 SSH 服务器
            tool_log.log.info(
                f"LJ - 链接[{self.bean_conn.url}:{self.bean_conn.port}:{self.bean_conn.app_key}:{self.bean_conn.app_secret}]创建开始...")
            client.connect(self.bean_conn.url, self.bean_conn.port,
                           self.bean_conn.app_key, self.bean_conn.app_secret)
            self.count += 1
            tool_log.log.info(f"LJ - 链接创建成功...{self.count}")
            self.ex_count = 0
            return client
        except:
            self.ex_count += 1
            tool_log.info(f"LJ - ssh 链接失败[{self.ex_count}]...")
            if self.ex_count > 5:
                return
            return self.gen_conn()

    def pool_conn(self):
        conn = self.pool.pop()
        try:
            scp = conn.open_sftp()
            return conn
        except:
            conn.close()
        finally:
            scp.close()

    def get_conn(self):
        if len(self.pool) > 0:
            return self.pool_conn() or self.gen_conn()
        else:
            return self.gen_conn()

    def put_conn(self, conn):
        self.pool.append(conn)


@tool_cache.lj_wrapper_cache(key="tool_ssh_init")
def init(bean_conn: lj_bean_conn.BeanConn):
    return LJSsh(bean_conn)


class LJSshWith:
    def __init__(self, bean_conn: lj_bean_conn.BeanConn) -> None:
        self.lj_ssh = init(bean_conn)

    def __enter__(self):
        self.curr = self.lj_ssh.get_conn()
        return self.curr

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            self.curr.close()
        else:
            self.lj_ssh.put_conn(self.curr)


class LSScpWith:
    def __init__(self, bean_conn: lj_bean_conn.BeanConn) -> None:
        self.lj_ssh = init(bean_conn)

    def __enter__(self):
        self.curr = self.lj_ssh.get_conn()
        # 创建scp 客户端
        self.scp = self.curr.open_sftp()
        return self.scp

    def __exit__(self, exc_type, exc_value, traceback):
        self.scp.close()
        if exc_type is not None:
            self.curr.close()
        else:
            self.lj_ssh.put_conn(self.curr)


def send_file(bean_conn: lj_bean_conn.BeanConn, local_file, remote_path):
    # 连接到对应AI服务器
    with LSScpWith(bean_conn) as sftp:
        dir = os.path.dirname(remote_path)
        try:
            sftp.stat(dir)
        except IOError:
            print(f"文件夹 '{dir}' 不存在, 开始创建...")
            sftp.mkdir(dir)

        sftp.put(local_file, remote_path)


def get_file(bean_conn: lj_bean_conn.BeanConn, remote_path, file_name):
    # 连接到对应AI服务器
    with LSScpWith(bean_conn) as sftp:
        img_name = f"temp/{file_name}"
        sftp.get(remote_path, img_name)
        return img_name


@tool_try.lj_no_except
def read_file(bean_conn: lj_bean_conn.BeanConn, remote_path):
    with LSScpWith(bean_conn) as sftp:
        with sftp.open(remote_path, "r") as remote_file:
            return remote_file.read()


def remove_file(bean_conn: lj_bean_conn.BeanConn, remote_path):
    with LSScpWith(bean_conn) as sftp:
        remove_file_sftp(sftp, remote_path)


def remove_file_sftp(sftp, remote_path):
    # 判定文件方式 - 根据有无后缀
    tool_log.info(f"LJ - ssh 删除文件[{remote_path}]")
    if not os.path.splitext(remote_path)[1]:
        sftp.rmdir(remote_path)
    else:
        sftp.remove(remote_path)


def list_file_and_children(bean_conn: lj_bean_conn.BeanConn, remote_path):
    # 查询文件列表，包含子文件，不包含文件夹
    with LSScpWith(bean_conn) as sftp:
        return __get_files_recursive(sftp, remote_path)


def __get_files_recursive(sftp, remote_directory):
    tool_log.info(f"读取文件{remote_directory}")
    file_list = []
    for item in sftp.listdir_attr(remote_directory):
        remote_path = remote_directory + '/' + item.filename
        if item.st_mode & stat.S_ISREG(item.st_mode):
            file_list.append({
                "filename": item.filename,
                "path": remote_path
            })
        else:
            file_list.extend(__get_files_recursive(sftp, remote_path))
            if len(file_list) < 1:
                remove_file_sftp(sftp, remote_path)
    return file_list


def list_dir(bean_conn: lj_bean_conn.BeanConn, remote_path):
    # 查询包含文件夹
    with LSScpWith(bean_conn) as sftp:
        return _get_dirs_recursive(sftp, remote_path)


def _get_dirs_recursive(sftp, remote_dir):
    tool_log.info(f"读取目录{remote_dir}")
    dir_list = []
    for item in sftp.listdir_attr(remote_dir):
        remote_path = remote_dir + '/' + item.filename
        dir_list.append({
            "filename": item.filename,
            "path": remote_path
        })

    return dir_list


def remove_dir(bean_conn: lj_bean_conn.BeanConn, remote_dir):
    with LSScpWith(bean_conn) as sftp:
        # 查找目录下所有文件
        dir_file_list = __get_files_recursive(sftp, remote_dir)
        for item in dir_file_list:
            remove_file_sftp(sftp, item.get("path"))

        # 删除目录
        remove_file_sftp(sftp, remote_dir)
